﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace Games.WPF.UI
{
    public class RubberbandAdorner : Adorner
    {
        #region Constructors

        public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
            : base(designerCanvas)
        {
            MouseMove += new MouseEventHandler(RubberbandAdorner_MouseMove);
            MouseUp += new MouseButtonEventHandler(RubberbandAdorner_MouseUp);
            
            DesignerCanvas = designerCanvas;
            StartPoint = dragStartPoint;
            RubberbandPen = new Pen(Brushes.LightSlateGray, 1);
            RubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
        }

        #endregion

        #region Properties

        private Point? StartPoint { get; set; }
        private Point? EndPoint { get; set; }
        private Pen RubberbandPen { get; set; }
        private DesignerCanvas DesignerCanvas { get; set; }

        #endregion

        #region Event Handlers

        private void RubberbandAdorner_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (!IsMouseCaptured)
                {
                    CaptureMouse();
                }

                EndPoint = e.GetPosition(this);
                UpdateSelection();
                InvalidateVisual();
            }
            else
            {
                if (IsMouseCaptured)
                {
                    ReleaseMouseCapture();
                }
            }

            e.Handled = true;
        }

        private void RubberbandAdorner_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Release mouse capture:
            if (IsMouseCaptured)
            {
                ReleaseMouseCapture();
            }

            // Remove adorner (=this) from adorner layer:
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(DesignerCanvas);
            if (adornerLayer != null)
            {
                adornerLayer.Remove(this);
            }

            e.Handled = true;
        }

        #endregion

        #region Methods

        private void UpdateSelection()
        {
            foreach (DesignerItem item in DesignerCanvas.SelectedItems)
            {
                item.IsSelected = false;
            }
            DesignerCanvas.SelectedItems.Clear();

            Rect rubberBand = new Rect(StartPoint.Value, EndPoint.Value);
            foreach (Control child in DesignerCanvas.Children)
            {
                DesignerItem item = child as DesignerItem;
                if (item != null)
                {
                    Rect itemRect = VisualTreeHelper.GetDescendantBounds(item);
                    Rect itemBounds = item.TransformToAncestor(DesignerCanvas).TransformBounds(itemRect);

                    if (rubberBand.Contains(itemBounds))
                    {
                        item.IsSelected = true;
                        DesignerCanvas.SelectedItems.Add(item);
                    }
                }
            }
        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);

            // Without a background the MouseMove event would not be fired:
            dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));

            if (StartPoint.HasValue && EndPoint.HasValue)
            {
                dc.DrawRectangle(Brushes.Transparent, RubberbandPen, new Rect(StartPoint.Value, EndPoint.Value));
            }
        }

        #endregion
    }
}